
COMMON INTELLIGENCE FACTOR AT THREE TIME POINTS (AGES 3, 5 AND 8) LINKING MATHS, SCIENCE AND READING SCORES WITH THE SAME FACTOR LOADINGS AT EACH OF THE THREE TIME POINTS.

ETA1   ETA2   ETA3

# simpler latent change score model with fewer constraints; has data in excel available
https://quantdev.ssri.psu.edu/sites/qdev/files/GMCh14_Common_Factor.html

#set filepath
filepath<-"https://quantdev.ssri.psu.edu/sites/qdev/files/ECLS_Science.csv"
#read in the .csv file using the url() function
eclsk <- read.csv(file=url(filepath),header=TRUE)
#looking at top of data file
head(eclsk)

config.invar<-'#factor loadings
               eta1 =~ lambda_S*s_g3+
                       lambda_R3*r_g3+ 
                       lambda_M3*m_g3
               eta2 =~ lambda_S*s_g5+
                       lambda_R5*r_g5+ 
                       lambda_M5*m_g5
               eta3 =~ lambda_S*s_g8+
                       lambda_R8*r_g8+ 
                       lambda_M8*m_g8
              #latent variable variances
                      eta1~~1*eta1
                      eta2~~eta2
                      eta3~~eta3
              #latent variable covariances
                      eta1~~eta2
                      eta1~~eta3
                      eta2~~eta3
              #unique variances
                      s_g3~~s_g3
                      s_g5~~s_g5
                      s_g8~~s_g8
                      r_g3~~r_g3
                      r_g5~~r_g5
                      r_g8~~r_g8
                      m_g3~~m_g3
                      m_g5~~m_g5
                      m_g8~~m_g8
              #unique covariances
                      s_g3~~s_g5
                      s_g3~~s_g8
                      s_g5~~s_g8
                      r_g3~~r_g5
                      r_g3~~r_g8
                      r_g5~~r_g8
                      m_g3~~m_g5
                      m_g3~~m_g8
                      m_g5~~m_g8
              #latent variable intercepts
                      eta1~0*1
                      eta2~1
                      eta3~1
              #observed variable intercepts
                      s_g3~tau_S*1
                      s_g5~tau_S*1
                      s_g8~tau_S*1
                      r_g3~tau_R3*1
                      r_g5~tau_R5*1
                      r_g8~tau_R8*1
                      m_g3~tau_M3*1
                      m_g5~tau_M5*1
                      m_g8~tau_M8*1'
lavaan.fit1<-lavaan(config.invar,
                data = eclsk,
                meanstructure = TRUE,
                estimator = "ML",
                missing = "fiml",
                                     fixed.x = FALSE)
summary(lavaan.fit1, fit.measures=TRUE)

ec <- data.frame(eclsk)
mean(ec[,2],na=T)
mean(ec[,3],na=T)
mean(ec[,4],na=T)
mean(ec[,5],na=T)
mean(ec[,6],na=T)
mean(ec[,7],na=T)
mean(ec[,8],na=T)
mean(ec[,9],na=T)
mean(ec[,10],na=T)

>>>>>>>>>>>>>>>>>>>

Different ability score means but same factor means and covariance structure between the ability scores over time

weak.invar<-'#factor loadings (with constraints)
               eta1 =~ lambda_S*s_g3+
                       lambda_R*r_g3+ 
                       lambda_M*m_g3
               eta2 =~ lambda_S*s_g5+
                       lambda_R*r_g5+ 
                       lambda_M*m_g5
               eta3 =~ lambda_S*s_g8+
                       lambda_R*r_g8+ 
                       lambda_M*m_g8
                #latent variable variances
                        eta1~~1*eta1
                        eta2~~eta2
                        eta3~~eta3
                #latent variable covariances
                        eta1~~eta2
                        eta1~~eta3
                        eta2~~eta3
                #unique variances
                        s_g3~~s_g3
                        s_g5~~s_g5
                        s_g8~~s_g8
                        r_g3~~r_g3
                        r_g5~~r_g5
                        r_g8~~r_g8
                        m_g3~~m_g3
                        m_g5~~m_g5
                        m_g8~~m_g8
                #unique covariances
                        s_g3~~s_g5
                        s_g3~~s_g8
                        s_g5~~s_g8
                        r_g3~~r_g5
                        r_g3~~r_g8
                        r_g5~~r_g8
                        m_g3~~m_g5
                        m_g3~~m_g8
                        m_g5~~m_g8
                #latent variable intercepts
                        eta1~0*1
                        eta2~1
                        eta3~1
                #observed variable intercepts
                        s_g3~tau_S*1
                        s_g5~tau_S*1
                        s_g8~tau_S*1
                        r_g3~tau_R3*1
                        r_g5~tau_R5*1
                        r_g8~tau_R8*1
                        m_g3~tau_M3*1
                        m_g5~tau_M5*1
                        m_g8~tau_M8*1'
lavaan.fit2<-lavaan(weak.invar,
                data = eclsk,
                meanstructure = TRUE,
                estimator = "ML",
                missing = "fiml",
                fixed.x = FALSE)
summary(lavaan.fit2, fit.measures=TRUE)

# strong invariance
# equal means and covariances over time

strong.invar<-'#factor loadings (with constraints)
               eta1 =~ lambda_S*s_g3+
                       lambda_R*r_g3+ 
                       lambda_M*m_g3
               eta2 =~ lambda_S*s_g5+
                       lambda_R*r_g5+ 
                       lambda_M*m_g5
               eta3 =~ lambda_S*s_g8+
                       lambda_R*r_g8+ 
                       lambda_M*m_g8
              #latent variable variances
                      eta1~~1*eta1
                      eta2~~eta2
                      eta3~~eta3
              #latent variable covariances
                      eta1~~eta2
                      eta1~~eta3
                      eta2~~eta3
              #unique variances
                      s_g3~~s_g3
                      s_g5~~s_g5
                      s_g8~~s_g8
                      r_g3~~r_g3
                      r_g5~~r_g5
                      r_g8~~r_g8
                      m_g3~~m_g3
                      m_g5~~m_g5
                      m_g8~~m_g8
              #unique covariances
                      s_g3~~s_g5
                      s_g3~~s_g8
                      s_g5~~s_g8
                      r_g3~~r_g5
                      r_g3~~r_g8
                      r_g5~~r_g8
                      m_g3~~m_g5
                      m_g3~~m_g8
                      m_g5~~m_g8
              #latent variable intercepts
                      eta1~0*1
                      eta2~1
                      eta3~1
              #observed variable intercepts (with constraints)
                      s_g3~tau_S*1
                      s_g5~tau_S*1
                      s_g8~tau_S*1
                      r_g3~tau_R*1
                      r_g5~tau_R*1
                      r_g8~tau_R*1
                      m_g3~tau_M*1
                      m_g5~tau_M*1
                      m_g8~tau_M*1'
lavaan.fit3<-lavaan(strong.invar,
                data = eclsk,
                meanstructure = TRUE,
                estimator = "ML",
                missing = "fiml",
                fixed.x = FALSE)
summary(lavaan.fit3, fit.measures=TRUE)

>>>>>>>>>>>>>>>>>

# has diagram of model on longitudinal maths data
https://longitudinalresearchinstitute.com/tutorials/chapter-16-latent-change-score-modeling/
# has no diagram but uses same maths data over tine
https://quantdev.ssri.psu.edu/sites/qdev/files/GM_Chp17_tutorial.html

dcm_math <- ' #opening quote
#MATHEMATICS
  #latent true scores (loadings = 1)
    lm1 =~ 1*math2
    lm2 =~ 1*math3
    lm3 =~ 1*math4
    lm4 =~ 1*math5
    lm5 =~ 1*math6
    lm6 =~ 1*math7
    lm7 =~ 1*math8

  #latent true score means (initial free, others = 0)  
    lm1 ~ 1
    lm2 ~ 0*1
    lm3 ~ 0*1
    lm4 ~ 0*1
    lm5 ~ 0*1
    lm6 ~ 0*1
    lm7 ~ 0*1

  #latent true score variances (initial free, others = 0)
    lm1 ~~ start(15)*lm1
    lm2 ~~ 0*lm2
    lm3 ~~ 0*lm3
    lm4 ~~ 0*lm4
    lm5 ~~ 0*lm5
    lm6 ~~ 0*lm6
    lm7 ~~ 0*lm7

  #observed intercepts (fixed to 0)
    math2 ~ 0*1
    math3 ~ 0*1
    math4 ~ 0*1
    math5 ~ 0*1
    math6 ~ 0*1
    math7 ~ 0*1
    math8 ~ 0*1

  #observed residual variances (constrained to equality)
    math2 ~~ sigma2_u*math2
    math3 ~~ sigma2_u*math3
    math4 ~~ sigma2_u*math4
    math5 ~~ sigma2_u*math5
    math6 ~~ sigma2_u*math6
    math7 ~~ sigma2_u*math7
    math8 ~~ sigma2_u*math8

  #autoregressions (fixed = 1)
    lm2 ~ 1*lm1
    lm3 ~ 1*lm2
    lm4 ~ 1*lm3
    lm5 ~ 1*lm4
    lm6 ~ 1*lm5
    lm7 ~ 1*lm6

  #latent change scores (fixed = 1)
    dm2 =~ 1*lm2
    dm3 =~ 1*lm3
    dm4 =~ 1*lm4
    dm5 =~ 1*lm5
    dm6 =~ 1*lm6
    dm7 =~ 1*lm7

  #latent change score means (constrained to 0)  
    dm2 ~ 0*1
    dm3 ~ 0*1
    dm4 ~ 0*1
    dm5 ~ 0*1
    dm6 ~ 0*1
    dm7 ~ 0*1

  #latent change score variances (constrained to 0)  
    dm2 ~~ 0*dm2
    dm3 ~~ 0*dm3
    dm4 ~~ 0*dm4
    dm5 ~~ 0*dm5
    dm6 ~~ 0*dm6
    dm7 ~~ 0*dm7

  #constant change factor (loadings = 1)
    g2 =~ 1*dm2 + 
          1*dm3 + 
          1*dm4 + 
          1*dm5 + 
          1*dm6 + 
          1*dm7 

  #constant change factor mean  
    g2 ~ start(15)*1

  #constant change factor variance
    g2 ~~ g2

  #constant change factor covariance with the initial true score
    g2 ~~ lm1

  #proportional effects (constrained equal)
    dm2 ~ start(-.2)*pi_m * lm1
    dm3 ~ start(-.2)*pi_m * lm2
    dm4 ~ start(-.2)*pi_m * lm3
    dm5 ~ start(-.2)*pi_m * lm4
    dm6 ~ start(-.2)*pi_m * lm5
    dm7 ~ start(-.2)*pi_m * lm6
' #closing quote
2.2 Model Estimation and Interpretation
We fit the model using lavaan.

#Model fitting
fit_math <- lavaan(dcm_math,
                data = nlsy_data, #note that fitting uses wide data
                meanstructure = TRUE,
                estimator = "ML",
                missing = "fiml",
                fixed.x = FALSE,
                mimic="mplus",
                control=list(iter.max=500),
                verbose=FALSE)